/**
 * 
 */
package co.fitstart.mobile.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.demo2do.core.BusinessException;
import com.demo2do.core.service.impl.GenericServiceImpl;
import com.demo2do.core.utils.DateFormatUtils;

import co.fitstart.entity.Constant;
import co.fitstart.entity.coupon.Coupon;
import co.fitstart.entity.course.Course;
import co.fitstart.entity.order.Order;
import co.fitstart.entity.order.OrderInvestigateRecord;
import co.fitstart.entity.order.OrderStatus;
import co.fitstart.entity.order.OrderType;
import co.fitstart.entity.order.PaymentStatus;
import co.fitstart.entity.product.Product;
import co.fitstart.entity.site.Site;
import co.fitstart.entity.user.Student;
import co.fitstart.entity.user.User;
import co.fitstart.entity.user.agent.Agent;
import co.fitstart.entity.user.agent.AgentDiscount;
import co.fitstart.entity.user.fit.UserFit;
import co.fitstart.mobile.dao.support.AgentDaoSupport;
import co.fitstart.mobile.entity.trading.Shopping;
import co.fitstart.mobile.service.OrderService;

/**
 * @author downpour
 *
 */
@Service("orderService")
public class OrderServiceImpl extends GenericServiceImpl<Order> implements OrderService {
    
    @Autowired
    private AgentDaoSupport agentDaoSupport;
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.weixin.service.OrderService#list(co.fitstart.common.entity.user.User, co.fitstart.common.entity.ecommerce.order.PaymentStatus)
     */
    @SuppressWarnings("unchecked")
    public List<Order> list(User user, PaymentStatus paymentStatus) {
        
        String querySentence = "FROM Order order WHERE order.user = :user AND order.paymentStatus = :paymentStatus ORDER BY order.payTime DESC, order.createTime DESC";
        
        Map<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("user", user);
        parameters.put("paymentStatus", paymentStatus);
        
        return genericDaoSupport.searchForList(querySentence, parameters);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.mobile.service.OrderService#list(co.fitstart.entity.order.OrderType, co.fitstart.entity.user.agent.Agent)
     */
    @SuppressWarnings("unchecked")
	public List<Order> listAgentOrder(OrderType orderType, Agent agent) {
    	
    	String sentence = "FROM Order WHERE disabled = false AND orderType = :orderType AND agent IS NOT NULL AND agent = :agent AND paymentStatus = :status";
    	
    	Map<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("orderType", orderType);
        parameters.put("agent", agent);
        parameters.put("status", PaymentStatus.PAID);
        
    	return genericDaoSupport.searchForList(sentence, parameters);
    }

    /* (non-Javadoc)
     * @see co.fitstart.weixin.service.OrderService#create(co.fitstart.weixin.entity.Shopping)
     */
    public Order create(Shopping shopping) {        
        // 1. generate order no
        String orderNo = shopping.createOrderNo();  // FIXME fix order no generate logic
        
        // 2. load product info
        Product product = genericDaoSupport.load(Product.class, shopping.getProductId());
        
        User user = genericDaoSupport.load(User.class, shopping.getUserId());
        
        //if experience order, check experience count
        if(OrderType.determineTo(product.getCourse()) == OrderType.INDIVIDUAL && product.getCourse().isExperience()) {
            checkExperience(user);
        }
        
        // 3. load user info & update user profile name if not exit
        user.setName(shopping.getContact().getContactPerson());
        if(product.getType().isOnline() && !product.isOnlineYear()) {
            UserFit fit = user.getUserFit() == null ? new UserFit() : user.getUserFit();
            fit.setHeight(shopping.getHeight());
            fit.setWeight(shopping.getWeight());
            user.editFit(fit);
        }
        genericDaoSupport.update(user);
        
        // 4. create order data and add related order attr
        Order order = shopping.createOrder();
        
        order.initialize(orderNo, user, product)
             .addAttribute("createTime", DateFormatUtils.format(order.getCreateTime(), "yyyy-MM-dd HH:mm:SS"));
        
        // 5. init contact with person and phone
        order.addAttribute("contactPerson", shopping.getContact().getContactPerson())
             .addAttribute("contactPhone", shopping.getContact().getContactPhone());
        
        if(shopping.withComment()) {
        	order.addAttribute("user_order_remarks", shopping.getComment());
        }
        
        // 6. initialize site for order
        if(shopping.withSite()) { 
            
            Site site = genericDaoSupport.load(Site.class, shopping.getSiteId());
            order.site(site);
            
            order.addAttribute("siteId", shopping.getSiteId());
        }
        
        // 7. bind coupon & calculate price
        if(shopping.withCoupon()) {
            
            Coupon coupon = genericDaoSupport.load(Coupon.class, shopping.getCouponId());
            order.calculatePrice(coupon);
            
            order.addAttribute("couponId", shopping.getCouponId());
            order.addAttribute("priceRemarks", coupon.getBatchName() + (coupon.getTemplate().getDiscountType().isPercent() ? "抵扣全额" : (coupon.getTemplate().getDiscountType().isFixedAmount() ? ("抵扣" + coupon.getAmount()/100 + "元") : "")));
            
            genericDaoSupport.update(coupon.occupy());
            
        }else {
            
            // calculate price, there could be some logic here to add
            order.calculatePrice();
        }
        
        // 8. bind discount code
        Course course = product.getCourse();
        if(shopping.withDiscountCode()) {
        	
            if(course.couldSelectCode()) {
                Student student = genericDaoSupport.searchForObject("FROM Student WHERE disabled = false AND offlineCode = :code", "code", shopping.getDiscountCode(), Student.class);
                if(student == null) {
                    throw new BusinessException("折扣码有误，请重新填写");
                }
                order.bindOfflineCode(student);
            } else {
                AgentDiscount agentDiscount = agentDaoSupport.loadAgentDiscount(shopping.getDiscountCode());
                if(agentDiscount == null) {
                    throw new BusinessException("折扣券码有误，请重新填写");
                }
                order.bindAgentDiscount(agentDiscount);
            }
        }
        
        // 9. init order type
        if(product.getType().isOnline() && product.isOnlineYear()) {
            order.initType(OrderType.ONLINE);
        } else {
            order.initType(OrderType.determineTo(course));
        }
        
        // 10. if product is online year, add order attr
        if(product.getType().isOnline() && product.isOnlineYear()) {
            order.addAttribute("isOnlineYear", "1");
        }
        
        // 11. if product type is others, save identificationCard and address
        if(product.getType().isOthers() && shopping.withOthers()) {
            order.addAttribute(Constant.IDENTIFICATION_CARD, shopping.getIdentificationCard());
            order.addAttribute(Constant.SHIPPING_ADDRESS, shopping.getAddress());
        }
        
        if(product.getType().isOnline() && !product.isOnlineYear() && shopping.getHourDifference() != null) {
            order.addAttribute("hour_difference", shopping.getHourDifference());
        }
        
        // 12. save into database
        genericDaoSupport.save(order);
        
        return order;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.weixin.service.OrderService#editShippingAddress(co.fitstart.common.entity.ecommerce.order.Order, java.lang.String)
     */
    public void editShippingAddress(Order order, String address) {
        order.addAttribute(Constant.SHIPPING_ADDRESS, address);
        genericDaoSupport.update(order);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.mobile.service.OrderService#loadOrderInvestigateRecord(co.fitstart.entity.order.Order)
     */
    public OrderInvestigateRecord loadOrderInvestigateRecord(Order order) {
        String querySentence = "FROM OrderInvestigateRecord WHERE order = :order";
        return genericDaoSupport.searchForObject(querySentence, "order", order, OrderInvestigateRecord.class);
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.mobile.service.OrderService#loadOrder(java.lang.Long)
     */
    public Order loadOrder(Long couponId) {
        String sentence = "SELECT attr.order FROM OrderAttribute attr WHERE attr.name = :name AND attr.value = :value AND attr.order.disabled = false";
        
        Map<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("name", "couponId");
        parameters.put("value", couponId.toString());
        
        return genericDaoSupport.searchForObject(sentence, parameters, Order.class);
    }
    
    /**
     * 
     * @param user
     */
    private void checkExperience(User user) {
        String sentence = "FROM Order WHERE user = :user AND orderType = :individual "
                        + "AND course.experience = true AND orderStatus in (:orderStatus) "
                        + "AND paymentStatus in (:paymentStatus) AND disabled = false";
        
        Map<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("user", user);
        parameters.put("individual", OrderType.INDIVIDUAL);
        parameters.put("orderStatus", new OrderStatus[]{OrderStatus.CREATED, OrderStatus.PENDING, OrderStatus.PROCESSING, OrderStatus.COMPLETE});
        parameters.put("paymentStatus", new PaymentStatus[]{PaymentStatus.UNPAID, PaymentStatus.PAID});
        
        if(genericDaoSupport.count(sentence, parameters) > 1) {
            throw new BusinessException("同一用户最多可上两次体验课");
        }
    }
}
